#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qrencode/3rd/qrencode.h"
#include <QKeyEvent>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QMessageBox>
#include <logindialog.h>
#include <QSettings>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QtScript>
#include <QtDebug>
#include <QVector>
#include <serialportthread.h>
#include <qmap.h>
#include <QSound>
#include <QProcess>
#include <uguiscreen.h>
#include <base64.h>
#include <QUdpSocket>
#include <QHostAddress>
#include<QCryptographicHash>

#define TIMER_TIMEOUT (30*1000)

QString serverIP="192.168.1.77";
qint16 serverPort=2060;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 移除标题栏
#if defined(Q_WS_QWS)
    this->setWindowFlags(Qt::FramelessWindowHint);
#endif

    // 设置黑色背景
    QPalette palette = this->palette();
    palette.setColor(QPalette::Background, QColor(0,0,0));
    this->setPalette(palette);

    //! [1]
    connect(ui->appQrButton,SIGNAL(clicked()),this,SLOT(ClickAppButton()));
    connect(ui->weQrButton,SIGNAL(clicked()),this,SLOT(ClickWeButton()));
    //connect(ui->serisetbtn,SIGNAL(clicked()),this,SLOT(ClickSeriSetButton()));

    //Port
    portThread = new SerialPortThread();
    connect(portThread, SIGNAL(SerialPortSignal(quint8,quint8*,int)), this, SLOT(OutSerialMesg(quint8,quint8*,int)));
    portThread->start();

    //Port With ScannerThread
    scannerThread = new ScannerThread();
    connect(scannerThread, SIGNAL(ScannerSignal(QByteArray)), this, SLOT(OutScannerMesg(QByteArray)));
    scannerThread->start();

    //Music Thread To Beep
    beepThread = new BeepThread();
    beepThread->start();


    //Second Screen
    uguiThread = new UguiThread();
    uguiThread->start();

    initialConfig();
    //connect(&networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(serviceRequestFinished(QNetworkReply*)));
    initialTable();
    udpSocket.bind(5824);
    connect(&udpSocket,SIGNAL(readyRead()),this,SLOT(processPendingDatagrams()));

    msgLog = new DebugLog();

}

void MainWindow::initialConfig(){
    // 配置文件路径
    QString dir = QCoreApplication::applicationDirPath();
    QString filename = dir + "/EPOS.ini";
    QSettings settings(filename, QSettings::IniFormat);

    settings.beginGroup("business");
    shopId = settings.value("code").toString();
    settings.endGroup();

    settings.beginGroup("server");
    QString ip = settings.value("serveruri").toString();
    QString port = settings.value("serverport").toString();
    basicUrl = "http://" + ip + ":" + port + "/e/";
    settings.endGroup();

    settings.beginGroup("machine");
    macId = settings.value("id").toString();
    settings.endGroup();

    //udp
    settings.beginGroup("udphost");
    QString hostAddress = settings.value("hostaddress").toString();
    uint hostPort = settings.value("hostport").toUInt();
    this->hostAddress=hostAddress;
    this->qHostAddress.setAddress(hostAddress);
    this->hostPort=hostPort;
    settings.endGroup();

}

void MainWindow::initialTable()
{
    standardItemModel = new QStandardItemModel(this);
    standardItemModel->setColumnCount(3);
    standardItemModel->setHeaderData(0, Qt::Horizontal, "菜品名称");
    standardItemModel->setHeaderData(1, Qt::Horizontal, "价格");
    standardItemModel->setHeaderData(2, Qt::Horizontal, "数量");

    ui->tableView->setModel(standardItemModel);
    ui->tableView->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter);
    ui->tableView->horizontalHeader()->setResizeMode(0, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(1, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(2, QHeaderView::Fixed);
    ui->tableView->setColumnWidth(0, 110);
    ui->tableView->setColumnWidth(1, 50);
    ui->tableView->setColumnWidth(2, 50);

    ui->tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    ui->tableView->verticalHeader()->hide();

    isPaying = false;
    tempStr = "";
}

void MainWindow::addTableline(QString name, QString price)
{
    if(tabList.contains(name)){
        tabList[name] = price;
    }
    else{
        tabList.insert(name, price);
    }

    if(standardItemModel->rowCount() > 0)
    {
        standardItemModel->removeRows(0, standardItemModel->rowCount());
    }

    uguiThread->Clear();

    QList<QString> names = tabList.keys();
    if(names.length() > 0)
    {
        for(int i = (names.length() - 1); i >= 0; i--)
        {
            QString dataline = tabList.value(names.at(i));
            QStringList list = dataline.split(',');
            if(list.count() == 2){
                QString pricet = list.at(0);
                QString numt = list.at(1);
                standardItemModel->setItem(i, 0, new QStandardItem(names.at(i)));
                standardItemModel->item(i, 0)->setTextAlignment(Qt::AlignCenter);
                standardItemModel->setItem(i, 1, new QStandardItem(pricet));
                standardItemModel->item(i, 1)->setTextAlignment(Qt::AlignCenter);
                standardItemModel->setItem(i, 2, new QStandardItem(numt));
                standardItemModel->item(i, 2)->setTextAlignment(Qt::AlignCenter);
            }

        }      

    }
}

void MainWindow::ClickAppButton(){
    char* str="lorytech";
    generateQRCode(str);
}

void MainWindow::generateQRCode(char* code){
    QRcode *qrcode = QRcode_encodeString(code , 7, QR_ECLEVEL_Q, QR_MODE_8, 1);
    QRect rect(0,0,180,180);
    if(0 != qrcode) {

        QGraphicsScene *scene = new QGraphicsScene;
        unsigned char *point = qrcode->data;
        scene->setSceneRect(0,0,180,180);
        scene->setItemIndexMethod(QGraphicsScene::NoIndex);
        //QPen qpen            //painter.setPen(Qt::NoPen);
        //painter.setBrush(this->qrBackground);
        //painter.drawRect(rect);
        QPen qpen(Qt::transparent,0,Qt::DashLine);
        QBrush qbrush(Qt::black,Qt::SolidPattern);
        int qrMargin=2;
        double scale = (rect.width () - 2.0 *qrMargin) / qrcode->width;
        //painter.setBrush(this->qrForeground);
        for (int y = 0; y < qrcode->width; y ++) {
            for (int x = 0; x < qrcode->width; x ++) {
                if (*point & 1) {
                    QRectF r(qrMargin + x * scale, qrMargin + y * scale, scale, scale);
                    scene->addRect(r,qpen,qbrush);
                }
                point ++;
            }
        }
        point = NULL;
        QRcode_free(qrcode);

        ui->graphicsView->setScene(scene);
        ui->graphicsView->show();
    }
}



void MainWindow::ClickWeButton(){
    //QString str("test");
    //writeData(str.toAscii());
    this->close();
}

void MainWindow::ClickSeriSetButton(){
    QMessageBox::about(this, "OpenScanner", "");
    scannerThread->openScanner();
}

void MainWindow::keyReleaseEvent(QKeyEvent *event){
//    if((event->key()>=Qt::Key_0 ) && (event->key()<=Qt::Key_9)){
//        ui->label->setText(ui->label->text()+event->key());
//    }else if(event->key()==Qt::Key_Back){
//        QString str=ui->label->text();
//        str.chop(1);
//        ui->label->setText(str);
//    }else if(event->key()==Qt::Key_Escape){
//        ui->label->setText("0.0");
//    }else if(event->key()==Qt::Key_Period){
//        ui->label->setText(ui->label->text()+event->key());
//    }
//    QString str = QString::number(event->key(), 16);
//    if(str.length() < 2) str = "0" + str;
//    str = "0x" + str;
//    QMessageBox::about(this, "key", str);
}

void MainWindow::addPayline(QString str)
{
    QString name, price;

        if(str.indexOf(".") == (str.length() - 1))
        {
            str.chop(1);
        }

        if(str == "0"){
            uguiThread->WriteAll(tempStr, tabList);
            return;
        }

        QString n;
        n.setNum(PayList.count());
        name = "N" + n;

        price = str + ",1";
        addTableline(name, price);
        PayList.insert(name, price);

        getTotal();
        tempStr = "";


}

void MainWindow::getTotal(){

    double total = 0;
    if(!PayList.isEmpty()){
        QList<QString> names = PayList.keys();
        if(names.length() > 0)
        {
            for(int i = (names.length() - 1); i >= 0; i--)
            {
                QString count = PayList.value(names.at(i));
                QStringList list = count.split(',');
                if(list.count() == 2){
                    QString price = list.at(0);
                    QString num = list.at(1);
                    double val = num.toDouble() * price.toDouble();
                    total = total + val;
                }
            }
        }
    }

    QString tstr;
    tstr.setNum(total);
    ui->label->setText(tstr);
    uguiThread->WriteAll(tstr, tabList);
    if(isPaying){
        timerStart();
        scannerThread->openScanner();
    }

}

void MainWindow::getTableline(QString str){
    QString url = basicUrl + "getprice?bcode=" + shopId + "&code=" + str;
    httpRequest.setUrl(QUrl(url));
    networkAccessManager.get(httpRequest);
}

void MainWindow::serviceRequestFinished(QNetworkReply *reply)
{
    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    if(reply->error() == QNetworkReply::NoError) {
        QByteArray resultArray=reply->readAll();
        QString result=resultArray;
        QScriptEngine engine;
        QScriptValue sc = engine.evaluate("value="+result);
        if(sc.property("returnType").toInt32()==1){
            if(sc.property("returnCode").toInt32()==200){
                QScriptValue dishes = sc.property("returnMessage");
                QString code = dishes.property("code").toString();
                QString name = dishes.property("name").toString();
                QString price = dishes.property("price").toString();

                int fen = price.toInt();
                double money = fen / 100;
                QString str;
                str.setNum(money);


                if(PayList.contains(code)){
                    QString num = PayList.value(code);
                    QStringList list = num.split(',');
                    if(list.count() == 2){
                        QString count = list.at(1);
                        int c = count.toInt();
                        c++;
                        count.setNum(c);
                        count = str + "," + count;
                        PayList[code] = count;
                        addTableline(name, count);
                    }
                }
                else{
                    price = str + ",1";
                    PayList.insert(code, price);
                    addTableline(name, price);
                }

                getTotal();
                tempStr = "";
            }
            else if(sc.property("returnCode").toInt32()==400){
                QString str = sc.property("returnMessage").toString();
                QString name, price;
                QString n;
                n.setNum(PayList.count());
                name = "N" + n;

                price = str + ",1";
                addTableline(name, price);
                PayList.insert(name, price);

                getTotal();
                tempStr = "";
            }
            else
            {
                QMessageBox::about(this, "提示", sc.property("returnMessage").toString());
                isPaying = false;
                timerStop();
            }
        }
        else if(sc.property("returnType").toInt32()==2){
            if(sc.property("returnCode").toInt32()==200){
                initial();
                ui->label->setText("余额：" + sc.property("returnMessage").toString() + "元");
            }
            else{
                //initial();
                //ui->label->setText(sc.property("returnMessage").toString());
                QString msg = sc.property("returnMessage").toString();
                QString fullMesg = msg + "。继续支付请点击确定，取消支付点击取消。";
                QMessageBox::about(this, "提示", fullMesg);
            }
            timerStop();
        }
        else if(sc.property("returnType").toInt32()==3){
            if(sc.property("returnCode").toInt32()==200){
                initial();
                ui->label->setText("余额：" + sc.property("returnMessage").toString() + "元");
            }
            else{
                //initial();
                //ui->label->setText(sc.property("returnMessage").toString());
                QString msg = sc.property("returnMessage").toString();
                QString fullMesg = msg + "。继续支付请点击确定，取消支付点击取消。";
                QMessageBox::about(this, "提示", fullMesg);
            }
            timerStop();
        }
    } else {
        QMessageBox::about(this, "提示", "服务请求失败");
        isPaying = false;
        timerStop();
    }
    reply->deleteLater();
}

void MainWindow::initial(){
    isPaying = false;
    tempStr = "";
    ui->label->setText("0");
    //uguiThread->WriteText("0");
    //uguiThread->Clear();
    if(PayList.count() > 0)
    {
        PayList.clear();
        tabList.clear();
        if(standardItemModel->rowCount() > 0)
        {
            standardItemModel->removeRows(0, standardItemModel->rowCount());
        }
    }

    uguiThread->WriteAll("0", tabList);
}

void MainWindow::keyPressEvent(QKeyEvent *event){

    QString str = ui->label->text();
    if(event->key()==Qt::Key_Escape){
        initial();
    }
    else
    {
        if(!isPaying){
            if((event->key()>=Qt::Key_0 ) && (event->key()<=Qt::Key_9))
            {
                //如果小数点长度超过2位 return
                if(tempStr.indexOf(".") != -1){
                    int num = tempStr.indexOf(".");
                    if((tempStr.length() - num) > 2) return;
                }
                //金额不能超过四位result
                if(tempStr.length() > 4) return;
                //将金额"0"改为""
                if(tempStr.length() == 1 && tempStr == "0") tempStr = "";
                tempStr = tempStr + event->key();
                ui->label->setText(tempStr);
                //uguiThread->WriteText(tempStr);
                uguiThread->WriteAll(tempStr, tabList);
            }
            else if(event->key()==Qt::Key_Backspace){

                if(tempStr.length() <= 1){
                    tempStr = "0";
                }
                else{
                    tempStr.chop(1);
                }
                ui->label->setText(tempStr);
                //uguiThread->WriteText(tempStr);
                uguiThread->WriteAll(tempStr, tabList);
            }
            else if(event->key()==Qt::Key_Period){
                if(tempStr.length() == 0) tempStr = "0";
                if(tempStr.indexOf(".") != -1) return;
                if(tempStr.length() > 4) return;
                int num = tempStr.toInt();
                tempStr.setNum(num);
                tempStr = tempStr + event->key();
                ui->label->setText(tempStr);
                //uguiThread->WriteText(tempStr);
                uguiThread->WriteAll(tempStr, tabList);
            }
            else if(event->key()==Qt::Key_Equal)
            {
                if(tempStr.length() > 0 && tempStr != "0")
                {
                    ui->label->setText(tempStr);
                    //uguiThread->WriteText(tempStr);
                    addPayline(tempStr);
                }
            }
            else if (event->key()==Qt::Key_Enter){
                isPaying = true;
                if(tempStr.length() > 0 && tempStr != "0")
                {
                    addPayline(tempStr);
                }
            }
        }
    }

}

void MainWindow::OutSerialMesg(quint8 cmd, quint8 *data, int len)
{

    QString title;
    QString desp;
    if(cmd == 0x20)
    {
        title = "Device Status";
        desp = quint8ToHexString(data, len);
    }
    else if(cmd == 0x21)
    {
        if(isPaying && len == 12){

            beepThread->beep();

            QString carid;
            for(int i = 0; i < 8; i++){
                QString str = QString::number(data[i], 16);
                if(str.length() < 2){
                    str = "0" + str;
                }
                carid += str;
            }

            quint32 money = 256 * 256 * 256 * data[8] + 256 * 256 * data[9] + 256 * data[10] + data[11];

            QString list;
            QList<QString> names = PayList.keys();
            if(names.length() > 0)
            {
                for(int i = 0; i < names.length(); i++)
                {
                    QString count = PayList.value(names.at(i));
                    list = list + names.at(i) + "," + count + ";";
                }
            }

            QString total = ui->label->text();
            double num = total.toDouble() * 100;
            total.setNum(num);

//            QString url = basicUrl + "paycard?bcode=" + shopId + "&mid=" + macId + "&carno=" + carid + "&total=" + total + "&list=" + list;
//            httpRequest.setUrl(QUrl(url));
//            networkAccessManager.get(httpRequest);
            QDateTime current_date_time =QDateTime::currentDateTime();
            QString current_date =current_date_time.toString("yyMMddHHmmssfff")+macId;
            QString AccountNo= carid;                        //AccountNo	卡账号	Number	用户一卡通卡账号	定位依据,不能同时为空
            QString Serialno="";                             //Serialno	卡序列号	String	序列号+扩展号 如果没有二次防碰创扩展号=”00000000”
            QString Price=total ;                            //	交易金额	Number	单位:元(两位小数)	非空	0.05
            QString sendMsg="1001|"+current_date+"|^"+macId+"|"+AccountNo+"|"+Serialno+"|"+Price+"|";
            sendDatagram(sendMsg);

        }
    }
    else if(cmd == 0x22)
    {
        title = "Pay Success";
        desp = quint8ToHexString(data, len);
    }
    else if(cmd == 0x23)
    {
        title = "Pay Error";
        desp = quint8ToHexString(data, len);
    }
}

void MainWindow::OutScannerMesg(const QByteArray &data)
{
    QString desp = "";
    if(!data.isNull() && data.length() > 0)
    {
        beepThread->beep();

        for(int i = 0; i < data.length(); i++)
        {
            desp.append(data.at(i));
        }

        if(desp.count() > 0 && isPaying){
            QString list;
            QList<QString> names = PayList.keys();
            if(names.length() > 0)
            {
                for(int i = 0; i < names.length(); i++)
                {
                    QString count = PayList.value(names.at(i));
                    list = list + names.at(i) + "," + count + ";";
                }
            }

            QString total = ui->label->text();
            double num = total.toDouble() * 100;
            total.setNum(num);
//          QString url = basicUrl + "payqrcode?bcode=" + shopId + "&mid=" + macId + "&code=" + desp + "&total=" + total + "&list=" + list;
//          httpRequest.setUrl(QUrl(url));
            timerStop();
            QString payCode= desp;
            QString Price=total ;      //	交易金额	Number	单位:元(两位小数)	非空	0.05
            QString sendMsg="1010|"+payCode+"|^"+macId+"|"+Price+"|";

            sendDatagram(sendMsg);
        }
    }
}

QString MainWindow::quint8ToHexString(quint8 *data, int len)
{

    QString result = "";
    for(int i = 0; i < len; i++)
    {
        QString str = QString::number(data[i], 16);
        if(str.count() < 2)
        {
            str = "0" + str;
        }
        str = "0x" + str;
        result += str + " ";
    }
    return result;
}

void MainWindow::timerStart()
{
    if(timerID != 0) timerStop();
    timerID = QObject::startTimer(TIMER_TIMEOUT);
}

void MainWindow::timerStop()
{
    if(timerID != 0) QObject::killTimer(timerID);
}

void MainWindow::timerEvent(QTimerEvent *event){
    if(event->timerId() == timerID)
    {
        QMessageBox::about(this, "title", "timeout");
        initial();
        ui->label->setText("支付超时");
        timerStop();
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

//将传入的原始报文转换成 base64报文
QString MainWindow::makeReport(QString originalMsg){

    QString report;
    QString base64msg;
    QString lengthInfo;
    QString strMD5;

    QByteArray byteArray;
    byteArray.append(originalMsg);
    QByteArray hash = QCryptographicHash::hash(byteArray, QCryptographicHash::Md5);
    strMD5 = hash.toHex();

    Base64 *base=new Base64();
    base64msg= base->encode(originalMsg.toUtf8());
    lengthInfo=QString("").sprintf("%04d",base64msg.length());
    report="A"+lengthInfo+base64msg+strMD5;

    return report;
}

//发送报文
void MainWindow::sendDatagram(QString sendText){
    msgLog->writelog("send 明文:"+sendText);
    QByteArray datagram;
    sendText=makeReport(sendText);
    datagram=sendText.toUtf8();
    QHostAddress address;
    address.setAddress(serverIP);
    udpSocket.writeDatagram(datagram,address,serverPort);
    msgLog->writelog("send :"+sendText);

}

//处理报文

void MainWindow::processPendingDatagrams(){
    QByteArray datagram;
    QString serverMsg="";
    do{
       datagram.resize(udpSocket.pendingDatagramSize());
       udpSocket.readDatagram(datagram.data(),datagram.size());
    }while(udpSocket.hasPendingDatagrams());
    QString rec_report=QString(datagram);

    msgLog->writelog("recive :"+rec_report);
    serverMsg=reConvert2Rport(rec_report);
    msgLog->writelog("recive 明文:"+serverMsg);
    ProcessServerReport(serverMsg);

}



//解析报文
QString MainWindow::reConvert2Rport(QString back_report){
    QString startFlag;      //起始符	1	报文起始标记符(A:请求；R:应答)
    QString strContentLength;      //明文Base64长度	4	4位十进制报文数据长度(Data长度，不包括MD5值)
    int contentlength;
    QString contentBase64;      //经过Base64编码的报文数据明文
    QString contentMd5;         //32	校验位：未经Base64编码的报文数据明文，经过MD5加密后转小写
    QString baseReport;

    baseReport="";
    if(back_report.length()>37){
        try{
            startFlag=back_report.mid(0,1);
            strContentLength=back_report.mid(1,4);
            contentlength=strContentLength.toInt();
            contentBase64=back_report.mid(5,contentlength);
            contentMd5=back_report.mid(5+contentlength,32);
            Base64 *base=new Base64();
            baseReport= base->decode(contentBase64);
            qDebug()<<"report:"<<baseReport<<endl;
        }catch(...){
            qDebug()<<"report:error"<<endl;
        }
    }else{
         qDebug()<<"report:too short"<<endl;
    }
    return baseReport;
}

inline QString GBK2UTF8(const QString &inStr)
{
    QTextCodec *gbk = QTextCodec::codecForName("GB18030");
    QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");

    QString g2u = gbk->toUnicode(gbk->fromUnicode(inStr));              // gbk  convert utf8
    return g2u;
}

//从解析后报文中获取信息
void MainWindow::ProcessServerReport(QString serverMsg){

    try{
        //1.根据^来分割报文头和报文体
        QString serverMsgHead=serverMsg.section('^',0,0);
        QString serverMsgbody=serverMsg.section('^',1,1);
        //1.1获取报文头部信息
        QString AskCode=serverMsgHead.section('|',0,0);     //AskCode	业务类型	String(4) 对应当前请求的业务类型。	非空	0001
        QString AskID=serverMsgHead.section('|',1,1);      //AskID	请求流水	String		可空	170503182347598004
        QString RepID=serverMsgHead.section('|',2,2);      // RepID	返回流水	String	一卡通业务流水	可空	00004785
        QString RepCode=serverMsgHead.section('|',3,3);    //RepCode	返回结果码	String(4)	0000:处理成功 XXXX:其他业务错误码见系统错误码表	非空	0000
        QString RepMsg=serverMsgHead.section('|',4,4);      //RepMsg	结果信息	String	描述处理情况	可空

        if(RepCode=="0000"){


            //付款成功  根据AskCode处理返回报文 1001|1803160004|880|0000||^0000030137|312102331|叶鹏鹏|1416830911111111|2985|1|459|19.35|6.32|0|0.00|0.00|
            if("1001"==AskCode){
                initial();
                QString leaveMoney=  serverMsgbody.section('|',7,7);
                ui->label->setText("余额：" + leaveMoney + "元");
                timerStop();
            }else if("1010"==AskCode){
                initial();
                QString leaveMoney=  serverMsgbody.section('|',6,6);
                ui->label->setText("余额：" + leaveMoney + "元");
                timerStop();
            }

        }else{
            isPaying = false;
            timerStop();
            ui->label->setText(" 错误:"+RepCode+RepMsg);
        }











    }catch(...){

        qDebug("服务器返回报文异常，无法交易！");

    }



}






